Repository navigation
for...in walks an object literal's fields; a generic's instance makes other instances (JSON.stringify({x: 1})) - #832
Merged
Conversation
… other instances
`function main() { print(JSON.stringify({x: 1})); }` exited with 0xC0000409 (exit code 3
without --opt) and printed nothing under every memory model. The default library threw its
TypeError for an object literal, by design, and nothing caught it. Two compiler gaps stood
in the way of writing the object instead:
- for...in over an object literal or a tuple used `.length` and failed to compile. It is
now made for each field of the type: `for (.i < N) { if (.i === 0) { const key = "a";
body } else if ... }`, so `obj[key]` is that field with its own type and break/continue
keep their meaning. An unnamed field's key is its position, and `t["1"]` and `"1" in t`
find it, as in JavaScript.
- GenericFunctionInfo::processing was one flag per generic function, so while
`f<number[]>` was being made, a call of `f<number>` from its body was taken for recursion
into an unfinished function and failed with "not all generic types can be identified".
`JSON.stringify([[1], [2]])` failed this way in any program that had not stringified a
number first. It is now the set of instances being made; another instance is made then,
up to 64 deep (`f<T>` calling `f<T[]>` would never end).
Tests: 00for_in_fields.ts, 00generic_instance_from_instance.ts (gc, own, rc, none; compile
and JIT), and the object half of 00for_in.ts, commented out until now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the body - A value field named get_x / set_x was taken for an accessor and walked as `x`, which then was not found. Only a function field drops the prefix. - The body is made once for each field, and an arrow function in it was named by its place in the source, so the second copy redefined the first's symbol. A copy's block now adds its key to every name made from a location while it is generated (MLIRHelper::anonymousNameCopy). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… default library) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
function main() { print(JSON.stringify({x: 1})); }built with--emit=exeexited with 0xC0000409 (--opt) or 3 (no--opt) and printed nothing, under every memory model.It was not a lowering crash. The default library threw
TypeError("JSON.stringify cannot read the fields of an object literal or a tuple")on purpose (DefaultLib #74 listed this as a limitation), and nothing caught it. Wrapped intry/catch, the program prints that message. To write the object instead, two things had to change in the compiler. The default-library side is ASDAlexander77/TypeScriptCompilerDefaultLib#95.1.
for...inover an object literal or a tupleIt used to desugar to an index loop over
.lengthand failed to compile ("Can't resolve property 'length'"). Now it is made once for each field of the type:obj[key]is that field, with its own type. A generic can walk an object literal's fields at compile time this way.breakandcontinuework.t["1"]and"1" in tnow find that field too. Before,t["1"]printed nothing and"0" in twasfalse.get_xkeeps its full name.MLIRHelper::anonymousNameCopy). Without that, an arrow function in the body redefined its symbol.00for_in.ts, commented out until now, is turned on.2. An instance of a generic function can make other instances of it
GenericFunctionInfo::processingwas one flag per generic function. So whilef<number[]>was being made, a call off<number>from its body was treated as recursion into an unfinished function, and failed with "not all generic types can be identified".On main,
print(JSON.stringify([1, 2]))does not compile when it is the program's first stringify. DefaultLib'sjson.tspasses only because it stringifies a number first.The flag is now the set of instances being made. Any other instance is made at that point, up to 64 deep:
f<T>callingf<T[]>would otherwise never end, and it reports an error, as before.Tests
00for_in_fields.ts00generic_instance_from_instance.tsBoth run under gc and own (compile and JIT, in their own entries) and under rc and none (through
TSLANG_CORPUS). Both fail on main.Verified locally (Windows x64)
tests.ps1passes for gc, rc, none and own, in release and debug, compiled and JIT.{"x":1}under every model, with and without--opt.Merge order
Merge this PR before ASDAlexander77/TypeScriptCompilerDefaultLib#95. The release workflow clones DefaultLib main, so its new
json.tscases fail with a compiler that does not have this change.Known limits, not changed here
{ 0: … }/{ "0": … }is written by JSON.stringify as an array, and a named tuple as an object. Named tuples and object literals share one type, so the two cannot be told apart.for (let k in obj)widens the key tostring, soobj[k]is rejected. Useconst.obj[key]there is a compile error.f(v, n - 1)fromf<T>) still fails. It does on main too: the instance's type is registered only after its body is discovered.-mm=own, an object literal holding a class instance ({ when: new Date(0) }) is still rejected by the existing own rule.🤖 Generated with Claude Code